<?php
	define('SERVICE_NAME', 'TI-Service');
	define('DISPLAY_NAME', 'PHP Service Application');
	
	define('PARENT_SIGNAL', 'Signal-For-Child');
	define('CHILD_SIGNAL', 'Signal-For-Parent');
	
	define('CHILD_START', 1);
	define('CHILD_STOP', 0);
	
	define('CHILD_READY_START', 1);
	define('CHILD_READY_STOP', 0);	
	
	define('TIME_FOR_SLEEP', 2);
	
	// 60 * 15 = 15 menit
	//define('TIME_FOR_CHECK', 900);			
	define('TIME_FOR_CHECK', 60); // 1 menit
	
	// 60 * 60 = 1 jam
	//define('TIME_FOR_ACTION', 3600);			
	define('TIME_FOR_ACTION', 180); // 3 menit			
	
	// For logging usage.
	require_once('service-log.php');
			
	if (empty($argv[1])) {
		// Parameter(s) unavailable...
		$str  = "Parameter harus tersedia : \n";
		$str .= "reg  	: Untuk melakukan proses registrasi service.\n";
		$str .= "unreg 	: Untuk melakukan proses hapus registrasi service.\n";
		$str .= "reslog	: Untuk melakukan proses reset file logging.\n";
		$str .= "status	: Untuk mendapatkan informasi service.\n";
		$str .= "Bagian TI - Jamkrindo.";
		die($str);
	} else {
		// Loading library...it's not loaded yet.
		setLog('Main : checking for win32service extension...');
		if (!extension_loaded('win32service')) {
			setLog('Main : loading win32service extension...');
			dl('php_win32service.dll') or die('Can not load library php_win32service.dll');
		}	
		
		// Parameter tersedia...
		switch (strtolower(trim($argv[1]))) {
			case 'reg' :
				// Registration.
				$message = 'Main : service registration...';
				setLog($message);
				echo $message;

				$result = win32_query_service_status(SERVICE_NAME);
				if ($result !== FALSE) {
					if (!is_array($result)) {
						win32_create_service(array(
							'service' => SERVICE_NAME,
							'display' => DISPLAY_NAME,
							'params' => __FILE__ . ' run'
						));					
					} else {
						$message = "\nMain : the service already registered...";
						setLog($message);
						echo $message;
					}
				} else {
					$message = "\nMain : cannot get service's information/status...";
					setLog($message);
					die($message);
				}
				
				break;
			case 'unreg' :
				// Delete registration.
				$message = 'Main : trying for deleting registration...';
				setLog($message);
				echo $message;
				
				$result = win32_query_service_status(SERVICE_NAME);
				if ($result !== FALSE) {
					if (!is_array($result)) {
						$message = "\nMain : there's no service for that name...";
						setLog($message);
						echo $message;									
					} else {
						$message = "\nMain : delete the service...";
						setLog($message);
						echo $message;
						win32_delete_service(SERVICE_NAME);
					}
				} else {
					$message = "\nMain : cannot get service's information/status...";
					setLog($message);
					die($message);
				}
												
				break;			
			case 'run' :
				// Running PHP Service.
				$message = 'Service : running PHP Service...';
				setLog($message);
				win32_start_service_ctrl_dispatcher(SERVICE_NAME);

				try {
					
					// Connecting...
					setLog('Service : connecting memcache server from service...');
					$memcache = new Memcache();
					if (!$memcache->connect('localhost')) {
						$message = 'Service : could not connect to memcache server!';
						setLog($message);
						throw new Exception($message);
					}
						
					// Set a value.
					setLog('Service : set a signal value in PARENT_SIGNAL => CHILD_START...');
					if (!$memcache->add(PARENT_SIGNAL, CHILD_START)) {
						$message = 'Service : can not initialiaze ' . PARENT_SIGNAL . ', exiting...';
						setLog($message);
						throw new Exception($message);
					}
					
																
					// Forking other process (co-process)...
					setLog('Service : forking co-process...');	
					$resource = popen('php ' . __FILE__ . ' child', 'r');
					
					// Wait for child to start.
					setLog('Service : waiting for child for starting...');
					while ($memcache->get(CHILD_SIGNAL) != CHILD_READY_START) {
						setLog('Service : sleeping for ' . TIME_FOR_SLEEP . ' second(s), wait for CHILD_SIGNAL => CHILD_READY_START...');
						sleep(TIME_FOR_SLEEP);
					}
					
					// Service loop...until got signal for stopping.
					setLog('Looping service...');
					while (WIN32_SERVICE_CONTROL_STOP != win32_get_last_control_message())  {
						setLog('Service : sleeping for ' . TIME_FOR_SLEEP . ' second(s), main looping service...');
						sleep(TIME_FOR_SLEEP);
					}
					
					// Give a signal to co-process and wait for terminating...
					setLog('Service : Giving signal to co-process for terminating, PARENT_SIGNAL => CHILD_STOP...');
					$memcache->set(PARENT_SIGNAL, CHILD_STOP, MEMCACHE_COMPRESSED, 0);
					
					// Then just wait...until co-process ready for stopping.
					while ($memcache->get(CHILD_SIGNAL) != CHILD_READY_STOP) {						
						setLog('Service : sleeping for ' . TIME_FOR_SLEEP . ', wait for CHILD_SIGNAL => CHILD_READY_STOP...');
						sleep(TIME_FOR_SLEEP);
						// Next ToDo : How to react if the child process throw an exception and die.
					}
					
					
					// Close co-process.
					setLog('Service : closing co-process...');
					pclose($resource);
					
					// Delete value.
					setLog('Service : delete value PARENT_SIGNAL...');
					$memcache->delete(PARENT_SIGNAL, 0);
					
					// Close the connection.
					setLog('Service : closing connection...');
					$memcache->close();
					
				} catch (Exception $e) {
					setLog('Service : exception...' . $e->getMessage());	
					die($e->getMessage());
				}
				
				setLog('Service : ending PHP Service...');
				
				break;
			case 'child' :
				// Running child process.				
				setLog('Child : starting co-process...');
				
				// Prepare for action.				
				$nextAction = time();
				setLog('Child : prepare for next action => ' . $nextAction);
				
				try {
					// Connecting...
					setLog('Child : connecting to memcache server from co-process...');	
					$memcache = new Memcache();
					if (!$memcache->connect('localhost')) {
						$message = 'Child : could not connect to memcache server!';
						setLog($message);
						throw new Exception($message);
					}
						
					// Create key for child's signal.
					setLog('Child : set a signal value CHILD_SIGNAL => CHILD_START...');
					if (!$memcache->add(CHILD_SIGNAL, CHILD_START)) {
						$message = 'Child : can not initialiaze ' . CHILD_SIGNAL . ', exiting...';
						setLog($message);
						throw new Exception($message);
					}
					
					// As long as the signal is CHILD_START..we could run forever...
					setLog('Child : looping co-process...');
					while ($memcache->get(PARENT_SIGNAL) == CHILD_START) {
						
						if (time() >= $nextAction) {							
							// If doing action then we must set $action = true. Otherwise we run action each TIME_FOR_CHECK.
							$action = false;
						
							// Do the action.
							require('move-file.php');
							
							// The next time for action is this time plus TIME_FOR_ACTION.
							if ($action)
								$nextAction = time() + TIME_FOR_ACTION;
						} else {
							// Just sleeping for next action.
							sleep(TIME_FOR_CHECK);
						}
						
						/**
						 * Note :
						 * - If we set TIME_FOR_ACTION lower than TIME_FOR_CHECK (or equal) then the action taken each TIME_FOR_CHECK.
						 * - If we didn't set $action = true, then the action taken each TIME_FOR_CHECK.
						 * - If we set TIME_FOR_ACTION higher than TIME_FOR_CHECK then the next action depends on the last action and TIME_FOR_ACTION.
						 */																															
					}
					
					// Ready for stoping.
					setLog('Child : ready for stoping...');
					if ($memcache->get(PARENT_SIGNAL) == CHILD_STOP)
						$memcache->set(CHILD_SIGNAL, CHILD_READY_STOP, MEMCACHE_COMPRESSED, 0);
					
				} catch (Exception $e) {
					setLog("Child : exception..." . $e->getMessage());	
					
					// Delete value.
					setLog('Child : delete value CHILD_SIGNAL after exception...');
					$memcache->delete(CHILD_SIGNAL, 0);					
					
					// Close the connection.
					setLog('Child : closing memcache connection from co-process after exception...');
					$memcache->close();								
					
					die($e->getMessage());		
				}
				
				// Delete value.
				setLog('Child : delete value CHILD_SIGNAL...');
				$memcache->delete(CHILD_SIGNAL, 0);
								
				// Close the connection.
				setLog('Child : closing memcache connection from co-process...');
				$memcache->close();								
				
				// Child process finish.
				setLog('Child : ending co-process...');
				
				break;
			case 'reslog' :
				resetLog();
				break;
			case 'status' :
				$message = "Main : check status PHP Service...\n";
				setLog($message);
				echo $message;
				$result = win32_query_service_status(SERVICE_NAME);
				if ($result !== FALSE) {
					if (is_array($result)) {
						print_r($result);
					} else {
						$message = "Main : there's no service for that name...";
						setLog($message);
						echo $message;
					}					
				} else {
					$message = "Main : cannot get service's information/status...";
					setLog($message);
					die($message);
				}
				break;
			default :
				// Invalid param(s)...
				$message = 'Main : invalid param(s)...';
				setLog($message);
				die($message);
		}
	}
	
	// End of file.